package com.ruoyi.web.controller.wnjk.app.registration;

import com.ruoyi.system.pay.domain.dto.PayRequestDTO;
import com.ruoyi.system.pay.domain.po.OrderQuery;
import com.ruoyi.system.pay.service.IPayService;
import com.ruoyi.system.wnjk.contents.Contents;
import com.ruoyi.system.wnjk.domain.po.WnjkRegistrationOrder;
import com.ruoyi.system.wnjk.producer.DirectProducer;
import com.ruoyi.system.wnjk.service.IWnjkRegistrationOrderService;
import com.ruoyi.system.wnjk.service.RegistrationInventoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/app/Registration")
public class RegistrationPaycontroller {

    @Autowired
    private IWnjkRegistrationOrderService wnjkRegistrationOrderService;  // 订单服务

    @Autowired
    private IPayService payService;  // 支付服务

    @Autowired
    private RegistrationInventoryService inventoryService;  // 库存服务

    @Autowired
    private RedisTemplate<String, String> redisTemplate;  // Redis 缓存服务

    @Autowired
    private PlatformTransactionManager transactionManager;  // 事务管理器

    @Autowired
    private DirectProducer directProducer;  // 消息队列生产者

    /**
     * 将字符串或其他类型转换为 Long 类型
     */
    private Long convertToLong(Object value) {
        if (value == null) return 0L;
        if (value instanceof Number) return ((Number) value).longValue();
        try {
            return Long.parseLong(value.toString());
        } catch (NumberFormatException e) {
            return 0L;
        }
    }

    /**
     * 创建或更新支付订单，使用 TransactionTemplate 管理事务
     *
     * @param requestData 请求体，包含 userId、outTradeNo（可选）、packageId、hospitalId、patientId、packagePrice、date 等
     * @return 支付宝支付表单字符串
     */
    @PostMapping("/pay")
    public String createOrContinuePayment(@RequestBody Map<String, Object> requestData) {

        //确保整个支付流程的原子性，如失败则回滚
        TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
        final String[] outTradeNoHolder = new String[1];
        String payForm = transactionTemplate.execute(new TransactionCallback<String>() {
            @Override
            public String doInTransaction(TransactionStatus status) {
                try {
                    System.out.println("Request data: " + requestData);

                    //没有 outTradeNo 则生成新的 UUID 作为订单号。
                    String outTradeNo = (String) requestData.get("outTradeNo");

                    //Redis 中检查是否已存在相同的未支付订单，防止重复提交。
                    boolean isNewOrder = (outTradeNo == null || outTradeNo.trim().isEmpty());

                    if (isNewOrder) {
                        outTradeNo = java.util.UUID.randomUUID().toString();
                        outTradeNoHolder[0] = outTradeNo;
                        String redisKey = "order:pending:" + outTradeNo;
                        if (redisTemplate.hasKey(redisKey)) {
                            throw new RuntimeException("订单已存在，请勿重复提交");
                        }
                    } else {
                        WnjkRegistrationOrder existingOrder = wnjkRegistrationOrderService.selectWnjkRegistrationOrderById(Long.valueOf(outTradeNo));
                        if (existingOrder == null) {
                            throw new RuntimeException("订单号 {" + outTradeNo + "} 不存在");
                        }
                        existingOrder.setOrderStatus("待支付");
                        existingOrder.setCreateTime(new Date());
                        wnjkRegistrationOrderService.updateWnjkRegistrationOrder(existingOrder);
                        outTradeNoHolder[0] = outTradeNo;
                    }

                    WnjkRegistrationOrder order = isNewOrder ? new WnjkRegistrationOrder() : wnjkRegistrationOrderService.selectWnjkRegistrationOrderById(Long.valueOf(outTradeNo));
                    order.setOrderNumber(outTradeNo);
                    Long userId = convertToLong(requestData.get("userId"));
                    if (userId == 0L) {
                        throw new RuntimeException("用户ID无效");
                    }
                    order.setUserId(userId);
                    order.setPatientId(convertToLong(requestData.get("patientId")));
                    order.setHospitalId(convertToLong(requestData.get("hospitalId")));
                    order.setDepartmentId(convertToLong(requestData.get("departmentId")));

                    Date appointmentTime;
                    if (requestData.get("date") != null) {
                        String dateStr = (String) requestData.get("date");
                        try {
                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                            appointmentTime = sdf.parse(dateStr);
                        } catch (Exception e) {
                            throw new RuntimeException("日期解析失败: " + dateStr, e);
                        }
                    } else {
                        appointmentTime = new Date();
                    }
                    order.setAppointmentTime(appointmentTime);

                    LocalDate appointmentDate = order.getAppointmentTime().toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDate();

                    if (isNewOrder) {
                        // 修改1：使用 InventoryService 的 deductStock 方法扣减库存
                        // 原因：deductStock 已包含分布式锁，确保并发安全，且支持按 AM/PM 扣减库存
                        boolean stockDeducted = inventoryService.deductStock("tomorrow", appointmentDate,  outTradeNo);
                        if (!stockDeducted) {
                            throw new RuntimeException("库存不足，无法创建订单");
                        }

                        String inventoryKey = buildInventoryKey("tomorrow", appointmentDate);
                        String redisKey = "order:pending:" + outTradeNo;
                        redisTemplate.opsForValue().set(redisKey, inventoryKey, 30, TimeUnit.MINUTES);
                    }
                    order.setDoctorId(Long.parseLong(requestData.get("doctorId")+""));
                    order.setOrderTime(new Date());
                    order.setPaymentMethod("支付宝");
                    order.setFee(new BigDecimal(requestData.get("packagePrice").toString()));
                    // 修改2：确保在插入新订单前设置 status 字段
                    // 原因：数据库表 status 字段为 NOT NULL，插入前必须设置值
                    order.setOrderStatus("待支付");
                    if (isNewOrder) {
                        order.setCreateTime(new Date());
                        java.util.Calendar cal = java.util.Calendar.getInstance();
                        cal.setTime(new Date());
                        cal.add(java.util.Calendar.MINUTE, 20);
                        wnjkRegistrationOrderService.insertWnjkRegistrationOrder(order);
                        System.out.println("【支付创建】新订单插入成功，outTradeNo: " + outTradeNo);
                    } else {
                        order.setUpdateTime(new Date());
                        wnjkRegistrationOrderService.updateWnjkRegistrationOrder(order);
                        System.out.println("【支付继续】订单更新成功，outTradeNo: " + outTradeNo);
                    }

                    PayRequestDTO payRequestDTO = new PayRequestDTO();
                    payRequestDTO.setOrderNumber(outTradeNo);
                    payRequestDTO.setSourceType(Contents.Pay.TYPE_TJ_PHYSICAL);
                    payRequestDTO.setSourceId(outTradeNo);
                    payRequestDTO.setAmount(order.getFee().toString());
                    payRequestDTO.setSubject("挂号订单支付");
                    payRequestDTO.setBody("挂号订单支付 - " + order.getDoctorId());

                    String payForm = payService.unifiedPay(payRequestDTO);
                    if (payForm == null || payForm.trim().isEmpty()) {
                        throw new RuntimeException("支付链接生成失败");
                    }

                    System.out.println("【支付创建/继续】支付链接生成成功: " + payForm);
                    return payForm;
                } catch (Exception e) {
                    System.err.println("【支付创建/继续】异常: " + e.getMessage());
                    status.setRollbackOnly();
                    throw new RuntimeException("创建/继续支付订单失败: " + e.getMessage(), e);
                }
            }
        });

        // 事务完成后发送消息
        try {
            OrderQuery orderQuery = new OrderQuery();
            orderQuery.setOrderNumber(outTradeNoHolder[0]);
            orderQuery.setSourceType(Contents.Pay.TYPE_TJ_PHYSICAL);
            directProducer.sendRequest(orderQuery);
        } catch (Exception e) {
            System.err.println("【支付创建/继续】消息发送失败: " + e.getMessage());
            // 可记录日志或重试，但不影响支付流程
        }

        return payForm;
    }

    /**
     * 定时检查超时订单
     *
     * @description 每 60 秒检查一次，判断订单的 ValidUntil 是否超时，将超时订单状态改为“已取消”
     */
    @Scheduled(fixedRate = 60000)
    public void checkExpiredOrders() {
        try {
            Date now = new Date();
            List<WnjkRegistrationOrder> expiredOrders = wnjkRegistrationOrderService.selectExpiredOrders();
            for (WnjkRegistrationOrder order : expiredOrders) {
                String redisKey = "order:pending:" + order.getOrderNumber();
                if ("待支付".equals(order.getOrderStatus()) && order.getValidUntil().before(now) && redisTemplate.hasKey(redisKey)) {
                    String inventoryInfo = redisTemplate.opsForValue().get(redisKey);
                    if (inventoryInfo != null) {
                        String[] parts = inventoryInfo.split(":");
                        String registrationId = String.valueOf(Long.parseLong(parts[1]));
                        LocalDate date = LocalDate.parse(parts[2]);
                        inventoryService.rollbackStock(registrationId, date, order.getOrderNumber());
                        order.setOrderStatus("已取消");
                        order.setUpdateTime(new Date());
                        wnjkRegistrationOrderService.updateExpiredOrder(order);
                        System.out.println("订单 {" + order.getOrderNumber() + "} 已超时取消，库存已恢复");
                        redisTemplate.delete(redisKey);
                    }
                }
            }
        } catch (Exception e) {
            System.err.println("超时处理异常: " + e.getMessage());
        }
    }

    private String buildInventoryKey(String registrationId, LocalDate date) {
        return "inventory:" + registrationId + ":" + date;
    }
}
